﻿// <copyright file="Window1.xaml.cs" company="Oleg V. Polikarpotchkin">
// Copyright © 2008 Oleg V. Polikarpotchkin. All Right Reserved
// </copyright>
// <author>Oleg V. Polikarpotchkin</author>
// <email>ov-p@yandex.ru</email>
// <date>2009-01-03</date>
// <summary>OpenWPFChart library. CurveChart Control Test app.</summary>
// <revision>$Id$</revision>

using System;
using System.Diagnostics;
using System.Linq;
using System.Windows;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Media;
using OpenWPFChart.Parts;

namespace CurveChartControlTest
{
	/// <summary>
	/// CurveChart Control Test app.
	/// </summary>
	public partial class Window1 : Window
	{
		public Window1()
		{
			InitializeComponent();

			// Bind to View.Zoom Command
			InputBindings.Add(new KeyBinding(NavigationCommands.Zoom, Key.Add // + at Numeric Pad
				, ModifierKeys.Control) { CommandParameter = 1.2 });
			InputBindings.Add(new KeyBinding(NavigationCommands.Zoom, Key.Subtract // - at Numeric Pad
				, ModifierKeys.Control) { CommandParameter = -1.2 });
			CommandBindings.Add(new CommandBinding(NavigationCommands.Zoom, ZoomCommandHandler));
		}

		/// <summary>
		/// Raises the <see cref="E:System.Windows.FrameworkElement.Initialized"/> event. This method is invoked whenever <see cref="P:System.Windows.FrameworkElement.IsInitialized"/> is set to true internally.
		/// </summary>
		/// <param name="e">The <see cref="T:System.Windows.RoutedEventArgs"/> that contains the event data.</param>
		protected override void OnInitialized(EventArgs e)
		{
			base.OnInitialized(e);
			chart.ApplyTemplate();
			
			chart.HorizontalAxisTitle = "Axis of abscissas";
			chart.VerticalAxisTitle = "Axis of ordinates";

			this.CommandBindings.Add(new CommandBinding(SelectTestCommand, SelectTestCommandExecute));

			Items_HardcodedCurvesTest();
		}

		#region HorizontalScale
		ChartScale horizontalScale = new ChartLinearScale() { Start = 0, Stop = 260, TickStep = 10 };
		/// <summary>
		/// Gets or sets the HorizontalScale property.
		/// </summary>
		/// <value>ChartScale value</value>
		public ChartScale HorizontalScale
		{
			get { return horizontalScale; }
			set { horizontalScale = value; }
		}
		#endregion HorizontalScale

		#region VerticalScale
		ChartScale verticalScale = new ChartLinearScale() { Start = 0, Stop = 250, TickStep = 10 };
		/// <summary>
		/// Gets or sets the VerticalScale property.
		/// </summary>
		/// <value>Finite positive value</value>
		public ChartScale VerticalScale
		{
			get { return verticalScale; }
			set { verticalScale = value; }
		}
		#endregion VerticalScale

		#region SelectTestCommand Command
		RoutedCommand selectTestCommand = new RoutedCommand();

		public RoutedCommand SelectTestCommand
		{
			get { return selectTestCommand; }
		}

		private void SelectTestCommandExecute(object sender, ExecutedRoutedEventArgs e)
		{
			string parameter = e.Parameter as string;
			Debug.Assert(!string.IsNullOrEmpty(parameter), "string.IsNullOrEmpty(parameter) == false");
			string[] tokens = parameter.Split(new char[]{ '_' });
			Debug.Assert(tokens.Length == 2, "tokens.Length == 2");

			chart.ItemsSource = null;
			if (chart.Items.Count > 0)
				chart.Items.Clear();
			switch (tokens[0])
			{
				case "Items":
					switch (tokens[1])
					{
						case "Hardcoded":
							Items_HardcodedCurvesTest();
							break;
						case "Polyline":
							Items_PolylineSampledCurvesTest();
							break;
						case "Bezier":
							Items_BezierSampledCurvesTest();
							break;
					}

					break;
				case "ItemsSource":
					switch (tokens[1])
					{
						case "Hardcoded":
							ItemsSource_HardcodedCurvesTest();
							break;
						case "Polyline":
							ItemsSource_PolylineSampledCurvesTest();
							break;
						case "Bezier":
							ItemsSource_BezierSampledCurvesTest();
							break;
					}
					break;
			}
		}
		#endregion SelectTestCommand Command

		#region Sample Data
		#region Items based tests
		private void Items_HardcodedCurvesTest()
		{
			Title = "Items based HardcodedCurvesTest";
			ItemDataView sinCurve = new HardcodedCurveDataView()
			{
				ItemData = new HardcodedCurveData<double, double>()
				{
					ItemName = "Sinus",
					Curve = Sinus
				},
				HorizontalScale = this.HorizontalScale,
				VerticalScale = this.VerticalScale,
				Pen = new Pen(Brushes.Red, 1)
			};
			chart.Items.Add(sinCurve);

			ItemDataView cosCurve = new HardcodedCurveDataView()
			{
				ItemData = new HardcodedCurveData<double, double>()
				{
					ItemName = "Cosinus",
					Curve = Cosinus
				},
				HorizontalScale = this.HorizontalScale,
				VerticalScale = this.VerticalScale
			};
			chart.Items.Add(cosCurve);
		}

		private void Items_PolylineSampledCurvesTest()
		{
			Title = "Items based PolylineSampledCurvesTest";
			double width = Math.Abs(Convert.ToDouble(HorizontalScale.Stop) - Convert.ToDouble(HorizontalScale.Start));
			double height = Math.Abs(Convert.ToDouble(VerticalScale.Stop) - Convert.ToDouble(VerticalScale.Start));

			// Sinus
			int pointCount = 10;
			double step = width / (pointCount - 1);
			DataPoint<double, double>[] points = new DataPoint<double, double>[pointCount];
			for (int i = 0; i < pointCount; ++i)
			{
				double x = i * step;
				double y = Sinus(x);
				points[i] = new DataPoint<double, double>(x, y);
			}
			GeometryDrawing pointMarker = new GeometryDrawing(Brushes.Brown, new Pen(Brushes.Red, 1)
				, new EllipseGeometry(new Point(0, 0), 4, 4));
			pointMarker.Freeze();
			ItemDataView sinSampledCurve = new SampledCurveDataView()
			{
				ItemData = new SampledCurveData<double, double>() 
				{ 
					ItemName = "Sinus", 
					Points = points 
				},
				HorizontalScale = this.HorizontalScale,
				VerticalScale = this.VerticalScale,
				Pen = new Pen(Brushes.Red, 1),
				PointMarker = pointMarker
			};
			chart.Items.Add(sinSampledCurve);

			// x^2
			pointCount = 10;
			step = width / (pointCount - 1);
			points = new DataPoint<double, double>[pointCount];
			for (int i = 0; i < pointCount; ++i)
			{
				double x = i * step;
				double y = height * (1 - x * x / (width * width));
				points[i] = new DataPoint<double, double>(x, y);
			}
			pointMarker = new GeometryDrawing(Brushes.BlueViolet, new Pen(Brushes.Blue, 1)
				, new RectangleGeometry(new Rect(-3, -3, 6, 6)));
			pointMarker.Freeze();
			ItemDataView x2SampledCurve = new SampledCurveDataView()
			{
				ItemData = new SampledCurveData<double, double>() 
				{ 
					ItemName = "x^2", 
					Points = points 
				},
				HorizontalScale = this.HorizontalScale,
				VerticalScale = this.VerticalScale,
				Pen = new Pen(Brushes.Red, 1),
				PointMarker = pointMarker
			};
			chart.Items.Add(x2SampledCurve);
		}

		private void Items_BezierSampledCurvesTest()
		{
			Title = "Items based BezierSampledCurvesTest";
			double width = Math.Abs(Convert.ToDouble(HorizontalScale.Stop) - Convert.ToDouble(HorizontalScale.Start));
			double height = Math.Abs(Convert.ToDouble(VerticalScale.Stop) - Convert.ToDouble(VerticalScale.Start));

			// Sinus
			int pointCount = 10;
			double step = width / (pointCount - 1);
			DataPoint<double, double>[] points = new DataPoint<double, double>[pointCount];
			for (int i = 0; i < pointCount; ++i)
			{
				double x = i * step;
				double y = Sinus(x);
				points[i] = new DataPoint<double, double>(x, y);
			}
			GeometryDrawing pointMarker = new GeometryDrawing(Brushes.Brown, new Pen(Brushes.Red, 1)
				, new EllipseGeometry(new Point(0, 0), 4, 4));
			pointMarker.Freeze();
			ItemDataView sinSampledCurve = new SampledCurveDataView()
			{
				ItemData = new SampledCurveData<double, double>() 
				{ 
					ItemName = "Sinus", 
					Points = points 
				},
				HorizontalScale = this.HorizontalScale,
				VerticalScale = this.VerticalScale,
				VisualCue = typeof(BezierVisual),
				Pen = new Pen(Brushes.Red, 1),
				PointMarker = pointMarker
			};
			chart.Items.Add(sinSampledCurve);

			// x^2
			pointCount = 10;
			step = width / (pointCount - 1);
			points = new DataPoint<double, double>[pointCount];
			for (int i = 0; i < pointCount; ++i)
			{
				double x = i * step;
				double y = height * (1 - x * x / (width * width));
				points[i] = new DataPoint<double, double>(x, y);
			}
			pointMarker = new GeometryDrawing(Brushes.BlueViolet, new Pen(Brushes.Blue, 1)
				, new RectangleGeometry(new Rect(-3, -3, 6, 6)));
			pointMarker.Freeze();
			ItemDataView x2SampledCurve = new SampledCurveDataView()
			{
				ItemData = new SampledCurveData<double, double>() 
				{ 
					ItemName = "x^2", 
					Points = points 
				},
				HorizontalScale = this.HorizontalScale,
				VerticalScale = this.VerticalScale,
				VisualCue = typeof(BezierVisual),
				Pen = new Pen(Brushes.Red, 1),
				PointMarker = pointMarker
			};
			chart.Items.Add(x2SampledCurve);
		}
		#endregion Items based tests

		#region ItemsSource based tests
		private void ItemsSource_HardcodedCurvesTest()
		{
			Title = "ItemsSource based HardcodedCurvesTest";
			ItemDataView[] curveDataView = 
			{
				new HardcodedCurveDataView() 
				{
					ItemData = new HardcodedCurveData<double, double>() 
					{
						ItemName="Sinus", 
						Curve = Sinus
					}, 
					HorizontalScale = this.HorizontalScale,
					VerticalScale = this.VerticalScale,
					Pen = new Pen(Brushes.Red, 1)
				},
				new HardcodedCurveDataView() 
				{
					ItemData = new HardcodedCurveData<double, double>() 
					{
						ItemName="Cosinus", 
						Curve = Cosinus
					}, 
					HorizontalScale = this.HorizontalScale,
					VerticalScale = this.VerticalScale,
					Pen = new Pen(Brushes.Green, 1)
				}
			};

			chart.ItemsSource = curveDataView;
		}

		private void ItemsSource_PolylineSampledCurvesTest()
		{
			Title = "ItemsSource based PolylineSampledCurvesTest";
			double width = Math.Abs(Convert.ToDouble(HorizontalScale.Stop) - Convert.ToDouble(HorizontalScale.Start));
			double height = Math.Abs(Convert.ToDouble(VerticalScale.Stop) - Convert.ToDouble(VerticalScale.Start));

			// Sinus
			int pointCount = 10;
			double step = width / (pointCount - 1);
			DataPoint<double, double>[] points = new DataPoint<double, double>[pointCount];
			for (int i = 0; i < pointCount; ++i)
			{
				double x = i * step;
				double y = Sinus(x);
				points[i] = new DataPoint<double, double>(x, y);
			}
			GeometryDrawing pointMarker = new GeometryDrawing(Brushes.Brown, new Pen(Brushes.Red, 1)
				, new EllipseGeometry(new Point(0, 0), 4, 4));
			pointMarker.Freeze();
			SampledCurveDataView sinCurveData = new SampledCurveDataView()
			{
				ItemData = new SampledCurveData<double, double>()
				{ 
					ItemName = "Sinus", 
					Points = points 
				},
				HorizontalScale = this.HorizontalScale,
				VerticalScale = this.VerticalScale,
				Pen = new Pen(Brushes.Blue, 1),
				PointMarker = pointMarker
			};

			// x^2
			pointCount = 10;
			step = width / (pointCount - 1);
			points = new DataPoint<double, double>[pointCount];
			for (int i = 0; i < pointCount; ++i)
			{
				double x = i * step;
				double y = height * (1 - x * x / (width * width));
				points[i] = new DataPoint<double, double>(x, y);
			}
			pointMarker = new GeometryDrawing(Brushes.BlueViolet, new Pen(Brushes.Blue, 1)
				, new RectangleGeometry(new Rect(-3, -3, 6, 6)));
			pointMarker.Freeze();
			SampledCurveDataView x2CurveData = new SampledCurveDataView()
			{
				ItemData = new SampledCurveData<double, double>() 
				{ 
					ItemName = "x^2", 
					Points = points 
				},
				HorizontalScale = this.HorizontalScale,
				VerticalScale = this.VerticalScale,
				Pen = new Pen(Brushes.Blue, 1),
				PointMarker = pointMarker
			};

			ItemDataView[] curveData = { sinCurveData, x2CurveData };

			chart.ItemsSource = curveData;
			//chart.SelectedIndex = 0;
		}

		private void ItemsSource_BezierSampledCurvesTest()
		{
			Title = "ItemsSource based BezierSampledCurvesTest";
			double width = Math.Abs(Convert.ToDouble(HorizontalScale.Stop) - Convert.ToDouble(HorizontalScale.Start));
			double height = Math.Abs(Convert.ToDouble(VerticalScale.Stop) - Convert.ToDouble(VerticalScale.Start));

			// Sinus
			int pointCount = 10;
			double step = width / (pointCount - 1);
			DataPoint<double, double>[] points = new DataPoint<double, double>[pointCount];
			for (int i = 0; i < pointCount; ++i)
			{
				double x = i * step;
				double y = Sinus(x);
				points[i] = new DataPoint<double, double>(x, y);
			}
			GeometryDrawing pointMarker = new GeometryDrawing(Brushes.Brown, new Pen(Brushes.Red, 1)
				, new EllipseGeometry(new Point(0, 0), 4, 4));
			pointMarker.Freeze();
			SampledCurveDataView sinCurveData = new SampledCurveDataView()
			{
				ItemData = new SampledCurveData<double, double>()
				{ 
					ItemName = "Sinus", 
					Points = points 
				},
				HorizontalScale = this.HorizontalScale,
				VerticalScale = this.VerticalScale,
				VisualCue = typeof(BezierVisual),
				Pen = new Pen(Brushes.Blue, 1),
				PointMarker = pointMarker
			};

			// x^2
			pointCount = 10;
			step = width / (pointCount - 1);
			points = new DataPoint<double, double>[pointCount];
			for (int i = 0; i < pointCount; ++i)
			{
				double x = i * step;
				double y = height * (1 - x * x / (width * width));
				points[i] = new DataPoint<double, double>(x, y);
			}
			pointMarker = new GeometryDrawing(Brushes.BlueViolet, new Pen(Brushes.Blue, 1)
				, new RectangleGeometry(new Rect(-3, -3, 6, 6)));
			pointMarker.Freeze();
			SampledCurveDataView x2CurveData = new SampledCurveDataView()
			{
				ItemData = new SampledCurveData<double, double>() 
				{ 
					ItemName = "x^2", 
					Points = points 
				},
				HorizontalScale = this.HorizontalScale,
				VerticalScale = this.VerticalScale,
				VisualCue = typeof(BezierVisual),
				Pen = new Pen(Brushes.Blue, 1),
				PointMarker = pointMarker
			};

			ItemDataView[] curveData = { sinCurveData, x2CurveData };

			chart.ItemsSource = curveData;
			//chart.SelectedIndex = 0;
		}
		#endregion ItemsSource based tests

		private double Sinus(double x)
		{
			double width = Math.Abs(Convert.ToDouble(HorizontalScale.Stop) - Convert.ToDouble(HorizontalScale.Start));
			double height = Math.Abs(Convert.ToDouble(VerticalScale.Stop) - Convert.ToDouble(VerticalScale.Start));
			return (1 + Math.Sin(Math.PI * x / (width / 2))) * height / 2;
		}

		private double Cosinus(double x)
		{
			double width = Math.Abs(Convert.ToDouble(HorizontalScale.Stop) - Convert.ToDouble(HorizontalScale.Start));
			double height = Math.Abs(Convert.ToDouble(VerticalScale.Stop) - Convert.ToDouble(VerticalScale.Start));
			return (1 + Math.Cos(Math.PI * x / (width / 2))) * height / 2;
		}
		#endregion Sample Data

		#region OpenWPFChart.Item element events handlers
		/// <summary>
		/// Handles the MouseEnterItem event of the OpenWPFChart.Item element.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="OpenWPFChart.MouseItemEventArgs"/> 
		/// instance containing the event data.</param>
		private void chartItem_EnterItem(object sender, MouseItemEventArgs e)
		{
			Cursor = Cursors.Hand;
		}

		/// <summary>
		/// Handles the MouseLeaveItem event of the OpenWPFChart.Item element.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="OpenWPFChart.MouseItemEventArgs"/> 
		/// instance containing the event data.</param>
		private void chartItem_LeaveItem(object sender, MouseItemEventArgs e)
		{
			Cursor = null;
		}

		/// <summary>
		/// Handles the Click event of the OpenWPFChart.Item element.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="OpenWPFChart.ClickEventArgs"/> 
		/// instance containing the event data.</param>
		private void chartItem_Click(object sender, ClickEventArgs e)
		{
			//MessageBox.Show(string.Format("Chart Item element of type {0} clicked"
			//    , e.OriginalSource.GetType()));
		}
		#endregion OpenWPFChart.Item element events handlers

		/// <summary>
		/// Execute <see cref="NavigationCommands.Zoom"/> command.
		/// </summary>
		/// <param name="sender">The sender.</param>
		/// <param name="e">The <see cref="System.Windows.Input.ExecutedRoutedEventArgs"/> instance containing the event data.</param>
		private void ZoomCommandHandler(object sender, ExecutedRoutedEventArgs e)
		{
			double zoom = 1.2;
			if (e.Parameter != null)
			{
				try
				{
					zoom = Convert.ToDouble(e.Parameter);
				}
				catch (Exception ex)
				{
					Trace.WriteLine("ZoomCommandHandler " + ex.Message);
					return;
				}
			}

			if (zoom == 0.0)
				return;
			if (zoom < 0.0)
				zoom = -1.0 / zoom;

			HorizontalScale.Scale *= zoom;
			VerticalScale.Scale *= zoom;
			
			foreach (ItemDataView item in chart.Items.OfType<ItemDataView>())
			{
				item.HorizontalScale.Scale *= zoom;
				item.VerticalScale.Scale *= zoom;
			}
		}

		/// <summary>
		/// Handles the Click event of the mnuViewCleanSelection menu item.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
		private void mnuViewCleanSelection_Click(object sender, RoutedEventArgs e)
		{
			chart.SelectedIndex = -1;
		}

		/// <summary>
		/// Handles the Click event of the Exit control.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
		private void Exit_Click(object sender, RoutedEventArgs e)
		{
			Close();
		}
	}
}
